package jdbc.util;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class BaseDao {

    //深度封装增删改查的对应代码！(被Mybatis框架代替！)
    //深度封装增删改代码！
    public static int executeDML(String sql, Object ... args) {
        //args：本质上就是装有要给问号赋值的数据的数组！
        //(1). 获取连接对象
        Connection conn = JDBCUtil.getConnection();
        PreparedStatement ps = null;
        int result = 0;
        try {
            //(2). 装载SQL语句
            ps = conn.prepareStatement(sql);
            //(3). 给问号占位符赋值！(看args数组的长度和数据！)
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            //(4). 执行SQL语句
            result = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //(5). 关闭资源
            JDBCUtil.close(null, ps, conn);
        }
        return result;
    }

    //深度封装查询代码
    public static <T> List<T> executeDQL(String sql, Class<T> c1, Object ... args) {
        //Class<T> c1：类的字节码信息，只有传递了类的字节码信息才能确定T到底是什么类型
        //(1). 获取连接对象
        Connection conn = JDBCUtil.getConnection();
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<T> list = new ArrayList<>();
        try {
            //(2). 装载SQL语句
            ps = conn.prepareStatement(sql);
            //(3). 动态给问号赋值
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            //(4). 执行SQL语句
            rs = ps.executeQuery();
            //(4.2)通过rs对象获取查询结果的信息！
            //rs.getMetaData()：将查询结果中的查询数据单独进行获取！
            ResultSetMetaData metaData = rs.getMetaData();
            //metaData：对象只包含所有查询结果的信息！

            //metaData.getColumnCount()：获取查询结果共有几列！
            //metaData.getColumnName(int index)：获取指定列号对应的列名！

            //(5). 将rs中的结果解析后装进List集合中存储并返回！
            while (rs.next()) {
                T t = c1.newInstance();//通过反射的方式创建T类对象！
                //问题：rs取几列数据和查询结果查询几列有关！
                //问题：取出的列的数据要放进实体类对象中存储！放在哪个成员变量里？
                //解决方案：必须知道查询结果有几列！每一列的列名叫什么！
                int columnCount = metaData.getColumnCount();
                //columnCount：查询结果一共包含几列！
                for (int i = 1; i <= columnCount; i++) {
                    //这个循环的目的是为了确定查询共有几列！确定一共需要get几次！
                    //问题：rs.getObject(i)这个值要往哪里装？实体类中的成员变量里装！
                    //给那个成员变量赋值！先知道列名是什么！
                    String columnLabel = metaData.getColumnLabel(i);
                    //columnName：指定列的列名！(根据列名找成员变量名！)
                    //根据反射的思想通过字节码文件获取类中的指定成员变量！
                    //根据指定的名称寻找类中的指定成员变量对应的字节码信息！
                    Field field = c1.getDeclaredField(columnLabel);
                    //field：表示指定列名对应的成员变量的字节码信息！
                    //释放权限：因为成员变量是被封装的！
                    field.setAccessible(true);
                    //通过反射的方式给指定的成员变量赋值！
                    field.set(t, rs.getObject(i));
//                    rs.getObject(i);//最终要往某一个成员变量中赋值！
                }

                //将t对象装进list集合中！
                list.add(t);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return list;
    }
}
